package cn.enjoy.design.behavior.strategy.springInitializingBean;


import cn.enjoy.design.behavior.strategy.springInitializingBean.service.ShopRankHandler;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 利用Spring框架中的InitializingBean接口与ApplicationContextAware接口来实现策略beans的自动装配。
 * InitializingBean接口中的afterPropertiesSet()方法在类的实例化过程当中执行，当客户端完成注入ShopRankHandlerFactory工厂类实例的时候，
 * afterPropertiesSet()也已经执行完成。因此可以通过重写afterPropertiesSet()方法，
 * 在其中利用getBeansOfType()方法来获取到策略接口的所有实现类，并存于Map容器之中，达到工厂类与具体的策略类解耦的目的。
 * <p>
 * 参考：https://mp.weixin.qq.com/s/Ovoy1CnN92xCYHbbO4H_DQ
 *
 * @author K
 * @date 2022-11-01 20:12
 */
@Component
public class ShopRankHandlerFactory implements InitializingBean, ApplicationContextAware {

    private ApplicationContext applicationContext;
    /**
     * 策略实例容器
     */
    private static Map<String, ShopRankHandler> GET_SHOP_RANK_STRATEGY_MAP;

    /**
     * 根据店铺类型获取对应的获取店铺卡片实现类
     *
     * @param shopType 店铺类型
     * @return 店铺类型对应的获取店铺卡片实现类
     */
    public static ShopRankHandler getStrategy(String shopType) {
        return GET_SHOP_RANK_STRATEGY_MAP.get(shopType);
    }

    @Override
    public void afterPropertiesSet() {
        Map<String, ShopRankHandler> beansOfType = applicationContext.getBeansOfType(ShopRankHandler.class);

        GET_SHOP_RANK_STRATEGY_MAP = Optional.ofNullable(beansOfType)
                .map(beansOfTypeMap -> beansOfTypeMap.values().stream()
                        .filter(shopRankHandle -> StringUtils.isNotEmpty(shopRankHandle.getType()))
                        .collect(Collectors.toMap(ShopRankHandler::getType, Function.identity())))
                .orElse(new HashMap<>(8));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

}